package com.apobates.jforum.grief.aurl;

import com.apobates.jforum.grief.aurl.convertor.AUrlMetaConvertor;
import com.apobates.jforum.grief.aurl.executor.AUrlMetaExecutor;
import com.apobates.jforum.grief.aurl.parser.AUrlParser;
import com.apobates.jforum.grief.aurl.parser.AntlrParser;
import com.apobates.jforum.grief.aurl.core.AUrlMeta;
import com.apobates.jforum.grief.aurl.core.AUrlMetaBuilder;
import com.apobates.jforum.grief.aurl.parser.PatternParser;
import com.apobates.jforum.grief.aurl.parser.AUrlParserException;
import com.apobates.jforum.grief.aurl.selector.AUrlMetaSelector;
import com.apobates.jforum.grief.aurl.selector.ActiveSelector;
import com.apobates.jforum.grief.aurl.spring.StringUtils;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 入口类/基准类
 */
public final class AUrl {
    private static Pattern urlRegex = Pattern.compile("^(http|https)://[-a-zA-Z0-9+&@#/%?=~_|,!:.;]*[-a-zA-Z0-9+@#/%=&_|]");

    /**
     * 通过正则表达式检查是否合法
     * 要求以:http或https开头
     * @param url url地址
     * @return 合法返回true
     */
    public static boolean isVerify(String url){
        if(!StringUtils.hasLength(url)){
            throw new IllegalArgumentException("参数不可用");
        }
        Matcher m = urlRegex.matcher(url);
        if (m.matches()) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 检查参数连接是否可访问
     * @param url url地址
     * @return 可访问返回true
     */
    public static boolean isActive(String url) {
        return ActiveSelector.isLived(url);
    }


    /**
     * 使用内置的解析器(AntlrParser)解析URL
     * 示例:
     *   AUrl.parse("http://www.baeldung.com/junit-5");
     * @param url 待解析的URL字符串
     * @return
     * @throws AUrlParserException
     */
    public static AUrlMeta parse(String url)throws AUrlParserException {
        try {
            return new AntlrParser().parse(url).build();
        }
        catch (AUrlParserException e){
            return new PatternParser().parse(url).build();
        }
        catch (Exception e){
            throw new AUrlParserException("无法解析目标参数: "+url);
        }
    }

    /**
     * 使用解析器实现来解析URL
     * 示例:
     *   AUrl.parse("http://www.baeldung.com/junit-5", new PatternParser());
     * @param url 待解析的URL字符串
     * @param parser 解析器实现
     * @return
     * @throws AUrlParserException
     */
    public static AUrlMeta parse(String url, AUrlParser parser) throws AUrlParserException{
        try {
            return parser.parse(url).build();
        }catch (Exception e){
            throw new AUrlParserException("无法解析目标参数: "+url+", 解析器: "+parser.getClass().getSimpleName());
        }
    }

    /**
     * 返回一个URL构建器
     * 示例:
     *   AUrl.create().scheme("http").host("www.baeldung.com").path("junit-5");
     * @return
     */
    public static AUrlMetaBuilder create(){
        return AUrlMetaBuilder.getInstance();
    }

    /**
     * 基于已知的URL来创建一个URL构建器
     * 示例:
     *   AUrl.create("http://www.baeldung.com/junit-5");
     * @param url 已知的URL
     * @return
     * @throws IllegalArgumentException
     */
    public static AUrlMetaBuilder create(String url) throws IllegalArgumentException{
        return AUrlMetaBuilder.fromUriString(url);
    }

    /**
     * 标准化参数地址
     * 示例:
     *   String t = normalize("http://www.example.com/app/#/home?a=1#b").orElse("about:blank");
     *   assert t.equals("http://www.example.com/app/home?a=1#b") :
     * @param url 参数地址
     * @return 参数不可用, 参数不以http开头或者标准化过程中出错返回Optional.empty
     */
    public static Optional<String> normalize(final String url) {
        return Optional.ofNullable(standard(url));
    }

    /**
     * 标准化参数地址
     * normalize的别名方法. 只不过返回值不同
     * @param url 参数地址
     * @return 参数不可用, 参数不以http开头或者标准化过程中出错返回 AUrlMetaBuilder.getInstance
     */
    public static AUrlMetaBuilder canonical(final String url){
        String tmp = standard(url);
        return AUrlMetaBuilder.fromUriString(tmp);
    }

    private static String standard(final String url)throws IllegalStateException, IllegalArgumentException{
        if(!isVerify(url)) {
            throw new IllegalArgumentException("参数不可用");
        }
        String pathSeparator = "/";
        String temp = isSPAUrl(url)?url.replace("/#", pathSeparator):url;
        try {
            URI uri = new URI(temp).normalize();
            return uri.toString();
        } catch (URISyntaxException e) {
            throw new IllegalStateException("使用URI.normalize失败");
        }
    }

    /**
     * 参数是否是一个SPA(Single Page Applications)模式的地址
     * SPA模式示例:
     *  hash模式: http://www.example.com/#home?a=1#b
     *  history模式: http://www.example.com/app/#/home?a=1#b
     * @param url 参数地址
     * @return 是返回true, 不是返回false
     */
    public static boolean isSPAUrl(final String url){
        // https://angular.io/guide/router#choosing-a-routing-strategy
        // https://router.vuejs.org/introduction.html
        // https://reactrouter.com/en/main/start/concepts
        if(!StringUtils.hasLength(url) || !url.startsWith("http")) {
            throw new IllegalArgumentException("参数不可用或不满足方法约定");
        }
        int lastQs = url.lastIndexOf("?");
        int firstPs = url.indexOf("://");
        String meta = lastQs == -1 ? url.substring(firstPs) : url.substring(firstPs, lastQs);
        return Arrays.stream(meta.split("/")).filter(ele->ele.contains("#")).count() > 0;
    }

    /**
     * 创建 AUrlMetaExecutor的实现类工厂
     * @param classIns AUrlMetaExecutor实现类的class. 例:PathParamExecutor.class
     * @return
     * @param <T>
     */
    public static <T> ExecutorFactory<T> execute(Class<? extends AUrlMetaExecutor<T>> classIns){
        return new ExecutorFactory<>(classIns);
    }

    /**
     * 创建 AUrlMetaSelector的实现类工厂
     * @param classIns AUrlMetaSelector实现类的class. 例:FileTypeSelector.class
     * @return
     * @param <T>
     */
    public static <T> SelectorFactory<T> select(Class<? extends AUrlMetaSelector<T>> classIns){
        return new SelectorFactory<>(classIns);
    }

    /**
     * 返回AUrlMetaConvertor的实现类工厂
     * @param convertor AUrlMetaConvertor实现类实例
     * @return
     * @param <T>
     */
    public static <T> ConvertorFactory<T> convert(final AUrlMetaConvertor<T> convertor){
        return new ConvertorFactory<>(convertor);
    }



    /**
     * AUrlMetaConvertor的实现类工厂
     * @param <T> 转换后的结果类型
     */
    public static class ConvertorFactory<T>{
        private final AUrlMetaConvertor<T> convertor;

        public ConvertorFactory(AUrlMetaConvertor<T> convertor) {
            this.convertor = convertor;
        }
        /**
         * 使用指定的解析器
         * @param parser AUrlParser实现类
         * @return 返回一个映射函数, 通过函数apply方法返回转换的结果
         */
        public Function<String, T> use(AUrlParser parser){
            return (String url)->AUrl.parse(url, parser).convert(convertor);
        }
        /**
         * 使用内置的解析器：PatternParser
         * @param url 待转换的目标地址
         * @return 返回转换的结果
         */
        public T arg(String url){
            T result = AUrl.create(url).build().convert(convertor);
            return result;
        }
    }

    /**
     * AUrlMetaExecutor的实现类工厂
     * @param <T> 执行过程中记录的类型
     */
    public static class ExecutorFactory<T>{
        private final Class<? extends AUrlMetaExecutor<T>> executor;

        public ExecutorFactory(Class<? extends AUrlMetaExecutor<T>> executor) {
            this.executor = executor;
        }

        /**
         * 使用指定的解析器
         * @param parser AUrlParser实现类
         * @return 返回一个映射函数, 通过函数apply方法返回执行器
         * @param <S> 执行器的类型
         */
        public <S> Function<String, S> use(AUrlParser parser){
            return (String url)->AUrl.parse(url, parser).execute(executor);
        }

        /**
         * 使用内置的解析器：PatternParser
         * @param url 待执行的目标地址
         * @return 返回执行器
         * @param <S> 执行器的类型
         */
        public <S> S arg(String url){
            S execute = AUrl.create(url).build().execute(executor);
            return execute;
        }
    }

    /**
     * AUrlMetaSelector的实现类工厂
     * @param <T> 选择结果的类型
     */
    public static class SelectorFactory<T> {
        private final Class<? extends AUrlMetaSelector<T>> selector;

        public SelectorFactory(Class<? extends AUrlMetaSelector<T>> selector) {
            this.selector = selector;
        }

        /**
         * 使用指定的解析器
         * @param parser AUrlParser实现类
         * @return 返回一个映射函数, 通过函数apply方法返回选择器
         * @param <S> 选择器的类型
         */
        public <S> Function<String, S> use(AUrlParser parser){
            return (String url)->AUrl.parse(url, parser).select(selector);
        }

        /**
         * 使用内置的解析器：PatternParser
         * @param url 选择的的目标地址
         * @return 返回选择器
         * @param <S> 选择器的类型
         */
        public <S> S arg(String url){
            S execute = AUrl.create(url).build().select(selector);
            return execute;
        }
    }
}
